package com.cicoding.uhfreader;


import com.cicoding.config.RscjaProperties;
import com.cicoding.config.UhfDevice;
import com.cicoding.config.WebSocket;
import com.cicoding.config.ZebraUHFProperties;
import com.cicoding.domian.KufangData;
import com.cicoding.utlis.JdbcUtils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.rscja.deviceapi.ConnectionState;
import com.rscja.deviceapi.entity.AntennaNameEnum;
import com.rscja.deviceapi.entity.AntennaState;
import com.rscja.deviceapi.interfaces.ConnectionStateCallback;
import com.rscja.deviceapi.interfaces.IUHFInventoryCallback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;


/**
 * @author Administrator
 */
@Slf4j
@Component
public class RscjaAsyncRead {

    @Resource
    private RscjaProperties rscjaProperties;

    /*@Resource
    private ExecutorService executorService;*/

    private ScheduledFuture<?> scheduledTask;



    /* 初始化过的读写器 */
    private Map<String, UhfDevice> initMaps = new HashMap<>();

    /* 正在读写的读写器 */
    private Map<String, UhfDevice> startRedMaps = new HashMap<>();

    private ConcurrentHashMap<String, Integer> ipJL = new ConcurrentHashMap<>();

    private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);



    /**
     * 初始化数据,之后的数据用来对比
     */
    private Cache<String, Long> cache  = CacheBuilder.newBuilder()
            .maximumSize(8000) // 可以根据需求设置缓存大小限制，比如1000条记录
            .build();
    /**
     * 盘点到的标签
     */
    Cache<String, Long>  RFIDCache = CacheBuilder.newBuilder()
            .expireAfterWrite(3000, TimeUnit.MINUTES)
            .build();
    /**
     * 数据库数据
     */
    Cache<String, String>  sqlData = CacheBuilder.newBuilder()
            .build();

    @Resource
    private WebSocket webSocket;

    @Value("${uhfReadOnOff.circuitChanger}")
    private Boolean circuitChanger;

    @Value("${uhfReadOnOff.readingTime}")
    private Integer readingTime;
    @Value("${uhfReadOnOff.periodTasks}")
    private Integer periodTasks;

    private boolean flage;

    /**
     * 读写器是否在读写
     *
     * @return
     */
    public boolean isStart() {
        return !startRedMaps.isEmpty();
    }

    /**
     * 监听标签数据
     */
    private final IUHFInventoryCallback getIuhfInventoryCallback() {
     //   System.out.println(uhftagInfo.getEPC());
        ////return uhftagInfo -> uhftagInfo.getEPC();
        return uhftagInfo -> {
            String code = uhftagInfo.getEPC();
            long timeMillis = System.currentTimeMillis();

            if (flage) {
                cache.put(code, timeMillis);
                log.error("--首轮打印标签---- {} ", code);
            } else {
                RFIDCache.put(code, timeMillis);
            }
        };
    }

    public  void query() throws Exception {
        Connection conn = JdbcUtils.getConnect();
        Statement stat = conn.createStatement();
        ResultSet rs = stat.executeQuery("select * from kufangxinxis");
        List<KufangData> list = new ArrayList<>();
        while (rs.next()) {
            sqlData.put(rs.getString("code"),rs.getString("name"));
        }
        JdbcUtils.close(conn, rs);
        // return list;
    }

    public void compareCachesAndPrintMessages(){
        Map<String, Long> cacheData = cache.asMap();
        //Map<String, Long> cacheData = NestedCacheExample.getFromNestedCacheData(IP).asMap();
        Map<String, Long> RFIDCacheData = RFIDCache.asMap();
        //Map<String, Long> RFIDCacheData = RFIDCacheExample.getFromNestedCacheData(IP).asMap();

        Iterator<Map.Entry<String, Long>> cacheIterator = cacheData.entrySet().iterator();
        while (cacheIterator.hasNext()) {
            Map.Entry<String, Long> entry = cacheIterator.next();
            String key = entry.getKey();
            if (!RFIDCacheData.containsKey(key)) {
                if (sqlData.asMap().containsKey(key)) {
                    String value = sqlData.getIfPresent(key);
                    System.out.println(key + " -  (出库) 工器具"+value);
                    webSocket.sendInfo(key + " -  (出库) 工器具"+value,"89");
                    cacheIterator.remove(); // Remove the data from cacheData
                }
            }
        }

        Iterator<Map.Entry<String, Long>> RFIDIterator = RFIDCacheData.entrySet().iterator();
        List<String> keysToAdd = new ArrayList<>();
        while (RFIDIterator.hasNext()) {
            Map.Entry<String, Long> entry = RFIDIterator.next();
            String key = entry.getKey();
            if (!cacheData.containsKey(key)) {
                if (sqlData.asMap().containsKey(key)) {
                    keysToAdd.add(key);
                    String value = sqlData.getIfPresent(key);
                    webSocket.sendInfo(key + " -  (入库) 工器具"+value,"89");
                    System.out.println(key + " -  (入库) 工器具"+value);
                }
            }
        }
        // System.out.println();

        String cache = "";

        for (Map.Entry<String, Long> entry : cacheData.entrySet()) {
            cache += entry.getKey() +" , ";
            // System.out.println("Tag: " + entry.getKey() + ", Value: " + entry.getValue());
        }
        String rfid = "";

        for (Map.Entry<String, Long> entry : RFIDCacheData.entrySet()) {
            rfid += entry.getKey() + " , ";
            //System.out.println("Tag: " + entry.getKey() + ", Value: " + entry.getValue());
        }

        System.out.println("\nRFID Cache Data: "+ cache);
        System.out.println("\nRFID rfid Data: "+ rfid);

        log.error("\nRFID Cache Data: {}", cache);
        log.error("RFID rfid Data: {}",rfid);
        // Add the new keys to cacheData
        for (String key : keysToAdd) {
            cacheData.put(key, System.currentTimeMillis());
        }
        try {
            //    webSocket.sendInfo("3333","89");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        RFIDCache.invalidateAll();
    }

    /**
     * 连接断开监听
     *
     * @param ip 读写器ip
     * @return
     */
    private final ConnectionStateCallback getConnectionStateCallback(String ip) {
        return (connectionState, o) -> {
            if (connectionState == ConnectionState.DISCONNECTED) {
                //判断是否是异常断开
                if (initMaps.containsKey(ip)) {
                    log.error("读写器{}异常断开，正在重新连接", ip);
                    boolean connect = false;
                    //如果是异常断开，重新连接
                    while (!connect) {
                        UhfDevice uhfDevice = initMaps.get(ip);
                        connect = uhfDevice.connect();
                        //判断当前是否处于读写状态
                        if (startRedMaps.containsKey(ip) && connect) {
                            if (circuitChanger) {
                                connect = startAsyncRed(uhfDevice);
                            } else {
                                connect = startRed(uhfDevice);
                            }
                        }
                        //如果连接失败，等待5秒后重新连接
                        if (!connect) {
                            try {
                                Thread.sleep(5000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        } else {
                            log.info("读写器-ip：{} 重新连接成功！", ip);
                        }
                    }
                }
            }
        };
    }

    /**
     * 设备初始化
     */
    public Boolean initReds() {
        boolean isInit = false;
        initMaps.clear();
        for (UhfDevice uhfDevice : rscjaProperties.getConfig()) {
            isInit = initRed(uhfDevice);
        }
        return isInit;
    }

    /**
     * 初始化单个设备
     *
     * @param uhfDevice 设备实体
     * @return
     */
    public Boolean initRed(UhfDevice uhfDevice) {
        boolean connect = uhfDevice.connect();
        if (connect) {
            List<AntennaState> antennaStateList = new ArrayList<>();
            int[] ants = Arrays.asList(uhfDevice.getAntArray().split(",")).stream().mapToInt(Integer::parseInt).toArray();
            for (int i : ants) {
                //设置天线频率
                connect = uhfDevice.setPower(AntennaNameEnum.getValue(i), rscjaProperties.getPower());
                //设置天线状态
                antennaStateList.add(new AntennaState(AntennaNameEnum.getValue(i), true));
            }
            //设置读写器
            connect = uhfDevice.setAntenna(antennaStateList);
            //设置读写器回调
            uhfDevice.setUhfRl(getIuhfInventoryCallback());
            //设置断开监听
            uhfDevice.setUhfRel(getConnectionStateCallback(uhfDevice.getIp()));
            if (connect) {
                initMaps.put(uhfDevice.getIp(), uhfDevice);
            }
        }
        log.info("读写器{}初始化{}", uhfDevice.getIp(), connect ? "成功" : "失败");
        return connect;
    }

    /**
     * 开启未开启的读写器
     */
    public void judgeOpen() {
        for (UhfDevice uhfDevice : rscjaProperties.getConfig()) {
            String ip = uhfDevice.getIp();
            if (!startRedMaps.containsKey(ip)) {
                if (initMaps.containsKey(ip)) {
                    log.info("读写器{}正在重新初始化", ip);
                    initRed(uhfDevice);
                }
                if (circuitChanger) {
                    startAsyncRed(uhfDevice);
                } else {
                    startRed(uhfDevice);
                }
            }
        }
    }

    /**
     * 开启读写器
     *
     * @return
     */
    public Boolean startTags() {
        log.info("开始盘存");
        AtomicBoolean isStart = new AtomicBoolean(false);
      //  startRedMaps.clear();
        for (UhfDevice uhfDevice : rscjaProperties.getConfig()) {
            if (circuitChanger) {
                isStart.set(startAsyncRed(uhfDevice) || isStart.get());
            } else {
                isStart.set(startRed(uhfDevice) || isStart.get());
            }
        }
        return isStart.get();
    }

    /**
     * 开关模式
     */
    public Boolean startAsyncRed(UhfDevice uhfDevice) {
        if (startRedMaps.containsKey(uhfDevice.getIp())) {
            return true;
        }
        log.info("开关模式读写-ip：{}" + uhfDevice.getIp());
        startRedMaps.put(uhfDevice.getIp(), uhfDevice);
      /*  executorService.execute(() -> {
            while (true) {
                if (!startRedMaps.containsKey(uhfDevice.getIp())) {
                    break;
                }
                String ip = uhfDevice.getIp();
                boolean startRed = startRed(uhfDevice);
                if (!startRed) {
                    startRedMaps.remove(ip);
                    break;
                }
                try {
                    Thread.sleep(periodTasks * 1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
        });*/
        return true;
    }

    /**
     * 开启读写
     *
     * @param uhfDevice 读写器实体
     * @return 开启成功 true
     */
    private boolean startRed(UhfDevice uhfDevice) {
        uhfDevice.setEPCMode();
        String ip = uhfDevice.getIp();
        if (!initMaps.containsKey(ip)) {
            return false;
        }
        log.info("开始读写---{}", ip);
        //开始盘点
        boolean redStart = false;
        if (circuitChanger) {
            redStart = uhfDevice.startInventoryTag();
            if (redStart) {
                try {
                    Thread.sleep(readingTime * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //停止盘点
                redStart = uhfDevice.stopInventory();
            }
        } else {
            if (initMaps.containsKey(ip)) {
                redStart = uhfDevice.startInventoryTag();
            }
            if (redStart) {
                startRedMaps.put(ip, uhfDevice);
            }
        }
        return redStart;
    }

    /**
     * 修改epc
     */
    public Boolean editEpc(String oldEpc, String newEpc) {
        Boolean editEpc = false;
        for (UhfDevice uhfDevice : rscjaProperties.getConfig()) {
            if (initMaps.containsKey(uhfDevice.getIp())) {
                stopRed(uhfDevice);
                if (!startRedMaps.containsKey(uhfDevice.getIp())) {
                    editEpc = uhfDevice.writeData(oldEpc, newEpc);
                    log.info("修改epc ip：{}-旧标签：{}-新标签：{}---结果：{}", uhfDevice.getIp(), oldEpc, newEpc, editEpc);
                    if (circuitChanger) {
                        startAsyncRed(uhfDevice);
                    } else {
                        startRed(uhfDevice);
                    }
                }
            }
        }
        return editEpc;
    }

    /**
     * 停止读写器 全部
     */
    public boolean stopRedAll() {
        boolean stopInventory = false;
        for (String ip : startRedMaps.keySet()) {
            stopInventory = startRedMaps.get(ip).stopInventory();
        }
        startRedMaps.clear();
        return stopInventory;
    }


    /**
     * 停止读写器 单个
     */
    private boolean stopRed(UhfDevice uhfDevice) {
        log.info("停止读写-ip：{}" + uhfDevice.getIp());
        boolean stopInventory = uhfDevice.stopInventory();
        if (stopInventory) {
            startRedMaps.remove(uhfDevice.getIp());
        }
        return stopInventory;
    }

    /**
     * 断开连接
     *
     * @return
     */
    public Boolean closeRed() {
        boolean disConnect = false;
        for (String ip : initMaps.keySet()) {
            disConnect = initMaps.get(ip).disConnect();
            log.info("断开连接-ip：{}" + ip);
        }
        initMaps.clear();
        return disConnect;
    }

    private boolean isFirstExecution = true; // 添加标志以判断是否是第一次执行
    private boolean isTaskScheduled = false; // 添加标志以判断任务是否已经被调度

    /**
     * 当执行这个定时任务时，如果在倒计时期间再次被调用，会取消之前的定时任务。
     * 在取消之前的任务后，重新计划一个新的任务。
     * 在延迟之前执行一些操作，比如记录日志和发送 WebSocket 信息。
     * 在延迟期间执行一些其他操作，比如通过 startReader 方法启动读取器。
     * 在延迟结束后执行具体的延迟任务，如果 isFirstExecution 为 false，则执行额外的比较任务等。
     * 如果在倒计时期间再次调用这个方法，会取消之前的定时任务，并且只有当倒计时结束之后，才会执行 isFirstExecution 里面的方法。
     * @param delayInSeconds
     */
    private ScheduledFuture<?> previousTaskFuture; // 用于存储上一个任务的引用
    public void scheduleTaskWithDelayAndClose(int delayInSeconds) {
        flage = false;
        if (isTaskScheduled) {
            // 如果任务已经被调度，取消之前的任务并重新计时延迟
            scheduledTask.cancel(true);
        }

        scheduledTask = executor.schedule(() -> {
            try {
                // 在延迟之前执行关闭方法
                // System.out.println("执行关闭其他方法...");
                log.error("--------------开始盘点 ---------");
                webSocket.sendInfo("开始盘点", "89");

                //startReader(zebraUHF);
                for (UhfDevice uhfDevice : rscjaProperties.getConfig()) {
                  //  initRed(uhfDevice);
                    startRed(uhfDevice);
                    try {
                        // 执行任务代码
                        Thread.sleep(100); // 每秒钟检查一次
                    } catch (InterruptedException e) {
                        // 处理中断异常
                        Thread.currentThread().interrupt(); // 清除中断状态
                    }
                }

                // 延迟指定秒数后执行任务
                scheduledTask = executor.schedule(() -> {
                    // 执行需要延迟执行的任务
                    if (!isFirstExecution) { // 如果不是第一次执行，则执行比较任务
                        compareCachesAndPrintMessages();
                       // stopReadTags();
                        stopRedAll();
                        webSocket.sendInfo("结束盘点", "89");
                    }
                    //  System.out.println("执行延迟任务...");

                }, delayInSeconds, TimeUnit.SECONDS);

                isFirstExecution = false; // 标记为不是第一次执行
                isTaskScheduled = true; // 标记任务已经被调度
            } catch (Exception e) {
                // 处理异常
                e.printStackTrace();
            }
        }, 0, TimeUnit.SECONDS);
    }


    public void scheduleTaskWithDelay(int delayInSeconds) {
        flage = true;
        executor.schedule(() -> {
            try {
                // 在延迟之前执行关闭方法
                // System.out.println("执行关闭其他方法...");
                //初始化的时候,如果有两个读写器需要都运行盘点
                //startReader(zebraUHFProperties.getConfigs().get(0));
                for (UhfDevice zebraUHF : rscjaProperties.getConfig()) {
                    //startReader(zebraUHF);
                    startRed(zebraUHF);
                }
                executor.schedule(() -> {
                    // 执行需要延迟执行的任务
                    stopRedAll();
                }, delayInSeconds, TimeUnit.SECONDS);
            } catch (Exception e) {
                // 处理异常
                e.printStackTrace();
            }
        }, 0, TimeUnit.SECONDS);
    }
}
